﻿using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace LogikBug.Collections
{
	public class ReadOnly<T> : IReadOnly<T>
	{
		#region Fields

		private T[] _array;
		private readonly IEnumerable<T> _enumerable;

		#endregion

		#region Constructors

		public ReadOnly(IEnumerable<T> array)
		{
			_enumerable = array.ThrowIfNull();
			Count = array.Count();
		}

		#endregion

		#region Properties

		public T this[int index]
		{
			get
			{
				if (_array == null)
				{
					_array = _enumerable.ToArray();
				}

				return _array[index];
			}
		}

		public int Count { get; private set; }

		public bool IsReadonly
		{
			get
			{
				return true;
			}
		}

		#endregion

		#region Methods

		#region Implicit operator overloads

		public static implicit operator T[](ReadOnly<T> @readonly)
		{
			return @readonly.ThrowIfNull().ToArray();
		}

		public static implicit operator ReadOnly<T>(T[] array)
		{
			return new ReadOnly<T>(array);
		}

		public static implicit operator List<T>(ReadOnly<T> @readonly)
		{
			return @readonly.ThrowIfNull().ToList();
		}

		public static implicit operator ReadOnly<T>(List<T> list)
		{
			return new ReadOnly<T>(list);
		}

		public static implicit operator Collection<T>(ReadOnly<T> @readonly)
		{
			return new Collection<T>(@readonly.ToList());
		}

		public static implicit operator ReadOnly<T>(Collection<T> list)
		{
			return new ReadOnly<T>(list);
		}

		public static implicit operator Queue<T>(ReadOnly<T> @readonly)
		{
			return new Queue<T>(@readonly.AsEnumerable());
		}

		public static implicit operator ReadOnly<T>(Queue<T> queue)
		{
			return new ReadOnly<T>(queue);
		}

		public static implicit operator Stack<T>(ReadOnly<T> @readonly)
		{
			return new Stack<T>(@readonly.AsEnumerable());
		}

		public static implicit operator ReadOnly<T>(Stack<T> stack)
		{
			return new ReadOnly<T>(stack);
		}

		#endregion

		public int IndexOf(T item)
		{
			return _enumerable.ToList().IndexOf(item);
		}

		public bool Has(T item)
		{
			return _enumerable.Contains(item);
		}

		public IEnumerator<T> GetEnumerator()
		{
			return _enumerable.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		#endregion
	}
}
